#!/usr/local/bin/python
#

"""A framework for writing cli applications"""

import sys
from optparse import OptionParser
import traceback


class Application(object):
    """Supplies the basic framework for a cli based application
    
    Your application descends from this class.  Descendent applications
    must at least implement the method run(self, opts, args).
    
    Options are set in configure_parser(self, opts).  Options is an
    optparse.OptionParser.
    
    """

    def __init__(self):
        self.options = None
        self.args = None
        self.argv = []

    def process_command_line(self):
        self.parser = OptionParser(usage=self.__doc__)
        self.configure_parser(self.parser)
        self.parse_command_line()

        
    
    def main(self, argv=None):
        """Run the application"""

        self.argv = self._argv(argv)
        try:
            self.process_command_line()
            self.check_options_and_args(self.options, self.args)
            self.run(self.options, self.args)
            return 0
        except AbnormalTermination, e:
            return self.abnormal_termination(e)
        except Terminate, e:
            return self.terminate(e)
        except SystemExit, e:
            return self.system_exit(e)
        except KeyboardInterrupt, e:
            return self.keyboard_interrupt(e)
        except UsageError, e:
            return self.usage_error(e)
        except Exception, e:
            return self.exception(e)

    def _argv(self, argv):
        if argv is None:
            return sys.argv
        else:
            return argv

    def parse_command_line(self):
        """Internal method that parses the command line.
    
        The command line is in self.argv.
        The options extracted are in self.options
        The arguments remaining are in self.args
        
        """
        try:
            (self.options, self.args) = self.parser.parse_args(self.argv)
        except SystemExit, e:
            if e.code == 2:
                raise UsageError()
        
    def configure_parser(self, parser):
        """Configure the OptionParser
        
        Your class overrides this method.

        """
        pass

    def check_options_and_args(self, options, args):
        """Your primary argument processing code goes here
        
        Your class overrides this method
        
        """
        pass

    def run(self, options, args):
        """This is your application's body.
        
        This is your application's main method.  It is overridden in your
        descendent class
        
        """
        pass

    def terminate(self, e):
        msg = str(e)
        if msg:
            print >> sys.stdout, msg
        return 0
        
    def keyboard_interrupt(self, e):
        traceback.print_exception(*sys.exc_info())
        return 2

    def system_exit(self, e):
        raise e
    
    def abnormal_termination(self, e):
        msg = str(e)
        if msg:
            print >> sys.stderr, msg
        return 1

    def usage_error(self, e):
        self.parser.print_usage(sys.stderr)
        return 2

    def exception(self, e):
        traceback.print_exception(*sys.exc_info())
        return 1


class AbnormalTermination(Exception):
    pass


class Terminate(Exception):
    pass

    
class UsageError(Exception):
    pass







